package com.qyb.base.java8.chap3;


import com.qyb.base.java8.bean.*;

import java.util.*;
import java.util.function.Function;

/**
 * *************************************************************************************************
 * <p/>
 * 实现功能：构造器引用
 * <p>
 * ------------------------------------------------------------------------------------------------
 * 版本          变更时间             变更人                     变更原因
 * ------------------------------------------------------------------------------------------------
 * 1.0.00      2017/8/7 17:05      秦有宝                     新建
 * <p/>
 * *************************************************************************************************
 */

public class ConstructorRef {
    public static void demo1(){
        List<Employee> es = new ArrayList<>();
        Employee e1 = new Employee();
        e1.setCode("001");
        e1.setId("1");
        e1.setName("小明");
        Function<Employee, Executor> c2 = Executor::new;
        Executor a2 = c2.apply(e1);


        Employee e2 = new Employee();
        e2.setCode("002");
        e2.setId("2");
        e2.setName("小明2");

        es.add(e1);
        es.add(e2);

        List<Executor> ets = new ArrayList<>();
        es.stream().filter(r-> r.getCode()!="001").forEach(r->{
            ets.add(c2.apply(r));
        });
        System.out.println("");

    }

    /*
        对于一个现有构造函数，你可以利用它的名称和关键字new来创建它的一个引用：ClassName::new。
        它的功能与指向静态方法的引用类似。例如，假设有一个构造函数没有参数。
        它适合Supplier的签名() -> Apple。你可以这样做：

        Supplier<Apple> c1 = Apple::new;    //构造函数引用指向默认的Apple()构造函数，等价于Supplier<Apple> c1 = () -> new Apple();
        Apple a1 = c1.get();                //调用Supplier的get方法将产生一个新的Apple

        如果你的构造函数的签名是Apple(Integer weight)，那么它就适合Function接口的签名
        Function<Integer, Apple> c2 = Apple::new;    //指向Apple(Integer weight)的构造函数引用，等价于Function<Integer, Apple> c2 = (weight) -> new Apple(weight);
        Apple a2 = c2.apply(110);                    //调用该Function函数的apply方法，并给出要求的重量，将产生一个Apple

        如果你有一个具有两个参数的构造函数Apple(String color, Integer weight)，那么它就适合BiFunction接口的签名，
        BiFunction<String, Integer, Apple> c3 = Apple::new; //指向Apple(String color, Integer weight)的构造函数引用,等价于BiFunction<String, Integer, Apple> c3 = (color, weight) -> new Apple(color, weight);
        Apple c3 = c3.apply("green", 110);                  //调用该BiFunction函数的apply方法，并给出要求的颜色和重量，将产生一个新的Apple对象

    构造函数引用
        你已经看到了如何将有零个、一个、两个参数的构造函数转变为构造函数引用。那要怎么
        样才能对具有三个参数的构造函数，比如Color(int, int, int)，使用构造函数引用呢？
        答案：你看，构造函数引用的语法是ClassName::new，那么在这个例子里面就是
        Color::new。但是你需要与构造函数引用的签名匹配的函数式接口。但是语言本身并没有提
        供这样的函数式接口，你可以自己创建一个：
        public interface TriFunction<T, U, V, R>{
            R apply(T t, U u, V v);
        }
        现在你可以像下面这样使用构造函数引用了：
        TriFunction<Integer, Integer, Integer, Color> colorFactory = Color::new;

     */
    public static void demo2(){
        List<Integer> weights = Arrays.asList(7, 3, 4, 10);
        List<Apple> apples = map(weights, Apple::new);
        System.out.println(apples);
    }
    public static List<Apple> map(List<Integer> list, Function<Integer, Apple> f){
        List<Apple> result = new ArrayList<>();
        for(Integer e: list){
            result.add(f.apply(e));
        }
        return result;
    }

    static Map<String, Function<Integer, Fruit>> map = new HashMap<>();
    static {
        map.put("apple", Apple::new);
        map.put("orange", Orange::new);
    }
    public static void demo3(){
        Fruit f = giveMeFruit("apple",120);
        System.out.println(f);

    }
    public static Fruit giveMeFruit(String fruit, Integer weight){
        return map.get(fruit.toLowerCase()).apply(weight);
    }

}
